import { AppSetting } from '../AppSetting';
import { Container, IService } from '../Container';
import { HelperTool } from './Common';

export class BaseGui implements IService {
    guiService = Container.defineProperty(GuiService);
    title: string = HelperTool.GetNull();
    gui: dat.GUI = HelperTool.GetNull();
    private _visible = false;
    get Visible() {
        return this._visible;
    }
    async Show(owner?: BaseGui) {
        if (!this.gui) {
            let rootGui = await this.guiService.rootGuiPromse;
            let parent = owner ? owner.gui : rootGui;
            this.gui = parent.addFolder(this.title);
        }
        this.UpdateGui();
        //this.gui.open();
        this.gui.show();
        this._visible = true;
        return this;
    }
    async Close() {
        if (this.gui)
            this.gui.hide();
        this._visible = false;
        return this;
    }
    async Refresh(){
        if(this.gui){
            this.UpdateGui();
        }
    }
    protected UpdateGui() {
    }
    Init() {
    }
    Level = 0;
}
class GuiService implements IService {
    AppSetting = Container.defineProperty(AppSetting);
    private GuiScriptUrl = ["dat.gui/build/dat.gui.js"
        , "jquery/dist/jquery.js"
        , "jquery-colpick/js/colpick.js"
        , "jquery-colpick/css/colpick.css"];
    allGui: dat.GUI = HelperTool.GetNull();
    rootGuiPromse: Promise<dat.GUI> = HelperTool.GetNull();
    Init() {
        this.rootGuiPromse = this.asyncInit();
    }
    private async asyncInit() {
        let baseUrl = this.AppSetting.GuiScriptBaseUrl;
        for (let _ of this.GuiScriptUrl) {
            if (_.endsWith(".css"))
                HelperTool.loadCSS(HelperTool.getFullUrl(_, baseUrl));
            else
                await HelperTool.loadScript(HelperTool.getFullUrl(_, baseUrl));
        }
        //@ts-ignore
        this.allGui = new dat.GUI({
            closeOnTop: true,
            width: 320
        });
        //@ts-ignore
        this.allGui.domElement.parentNode.style.zIndex = '1';
        this.allGui.close();
        return this.allGui;
    }

    /**
     *
     * @param {dat.GUI} gui3
     * @param {{name:string,state:boolean}[]} list
     * @param {(item)=>{}} checkChanged
     */
    private showGUIList<T extends { name: string; state: boolean; }>(gui3: dat.GUI, list: T[], checkChanged: (item: T) => void) {
        var dataList = {} as any;
        var oldDataList = {} as any;
        for (let { name, state } of list) {
            dataList[name] = state;
            oldDataList[name] = state;
            gui3.add(dataList, name).onChange(_ => {
                for (let name in dataList) {
                    if (dataList[name] != oldDataList[name]) {
                        oldDataList[name] = dataList[name];
                        list.forEach(_ => {
                            if (_.name == name) {
                                _.state = oldDataList[name];
                                checkChanged(_);
                            }
                        });

                    }
                }
            });
        }
    }
    buildGUIByObject(gui3: dat.GUI, funAny: any, funEvent?: any) {
        for (let key in funAny) {
            if (key.startsWith("_"))
                continue;
            let t = funAny[key] instanceof Array ? gui3.addColor(funAny, key) : gui3.add(funAny, key);
            if (funAny[key] instanceof Array)
                this.buildColor(gui3, t, funAny, key);

            this.buildEvent(t, funAny, key);
            if (funEvent)
                this.buildEvent(t, funEvent, key);
            
            //t.name(`*${key}`);
        }
    }
    private buildEvent(t: dat.GUIController, funAny: any, key: string) {
        if (funAny[`_${key}Options`]) {
            t = t.options(funAny[`_${key}Options`]());
        }
        if (funAny[`_${key}Range`]) {
            let range = funAny[`_${key}Range`]() as { step: number, min: number, max: number };
            if (range.min != undefined)
                t = t.min(range.min);
            if (range.max != undefined)
                t = t.max(range.max);
            if (range.step != undefined)
                t = t.step(range.step);
        }
        if (funAny[`_${key}Change`]) {
            t = t.onChange(funAny[`_${key}Change`]);
        }
        if (funAny[`_${key}Changed`]) {
            t = t.onFinishChange(funAny[`_${key}Changed`]);
        }

        if (funAny[`_Change`]) {
            t = t.onChange(funAny[`_Change`]);
        }
        if (funAny[`_Changed`]) {
            t = t.onFinishChange(funAny[`_Changed`]);
        }
    }
    private buildColor(gui3: dat.GUI, t: dat.GUIController, funAny: any, key: string) {
        let elementID = HelperTool.uuid();
        //@ts-ignore
        t.domElement.parentElement.id = elementID;
        //@ts-ignore
        $(`#${elementID}`).colpick({
            onShow: (dom: HTMLDivElement) => {
                dom.style.zIndex = '10';
                let color = funAny[key] as number[];
                //@ts-ignore
                $(`#${elementID}`).colpickSetColor({ r: color[0], g: color[1], b: color[2] });
            },
            onChange: (hsb: any, hex: any, rgb: any) => {
                funAny[key] = [rgb.r, rgb.g, rgb.b]
                gui3.updateDisplay();
                if (funAny[`_${key}Change`])
                    funAny[`_${key}Change`]();
                if (funAny[`_${key}Changed`])
                    funAny[`_${key}Changed`]();
            }
        });
    }
}